home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Library / +ORC / Orc pac 2 / FILEZ.ZIP / PERISCOP.ZIP / USEREXIT.ASM < prev    next >
Encoding:
Assembly Source File  |  1993-06-18  |  28.2 KB  |  1,238 lines

  1. cseg    segment para public 'code'
  2. org    100h
  3. userexit proc far
  4.  
  5. ; The following equate should be set by the assembler.
  6. ;    ps32    equ 0        ; 0 for 16-bit support, 1 for 32-bit support
  7.  
  8.     ; This program is an example of a memory-resident routine that is
  9.     ; used to contain user breakpoints and user exits from Periscope.
  10.     ; This program is attached to an unused interrupt vector so that it
  11.     ; can be called from Periscope. The allowable range of vectors is
  12.     ; 60H to FFH. This routine must be loaded into memory before Periscope
  13.     ; is run. When PS.COM is run, be sure to specify the '/I:nn' installa-
  14.     ; tion option, where nn is the interrupt vector.
  15.  
  16.     ; On entry, register AH contains a function number set by Periscope. For
  17.     ; the user breakpoints, (BU 1 through 8), AH will be from 1 to 8. For
  18.     ; the user exits (/U nn), AH will be from 9 to FFH. Note: F0 through FF
  19.     ; are reserved for use by Periscope. The reserved functions are:
  20.     ; F0 -- invoked after each command is entered, so that your code can
  21.     ;   modify the command line as needed.
  22.     ; F1 -- invoked before a short boot (QS), so that your code can perform
  23.     ;   any required cleanup
  24.     ; F2 -- invoked before a normal boot (QB)
  25.     ; F3 -- invoked before a long boot (QL)
  26.  
  27.     ; On entry, DS:SI points to a table containing the current program's
  28.     ; register values and other information. The information available is
  29.     ; shown in the following structure:
  30.  
  31. UserArgs struc
  32.  
  33. if ps32            ; if 32-bit
  34.  
  35. UserEAX    dd ?            ; the eax register
  36. UserEBX    dd ?            ; the ebx register
  37. UserECX    dd ?            ; the ecx register
  38. UserEDX    dd ?            ; the edx register
  39. UserESP    dd ?            ; the esp register
  40. UserEBP    dd ?            ; the ebp register
  41. UserESI    dd ?            ; the esi register
  42. UserEDI    dd ?            ; the edi register
  43. UserEIP    dd ?            ; the eip register
  44. UserDS    dw ?            ; the ds register
  45. UserES    dw ?            ; the es register
  46. UserSS    dw ?            ; the ss register
  47. UserCS    dw ?            ; the cs register
  48. UserFS    dw ?            ; the fs register
  49. UserGS    dw ?            ; the gs register
  50. UserEFL    dd ?            ; the eflags register
  51.  
  52.                 ; extra registers
  53. UserGDT dw ?            ; the gdt register (base & limit)
  54.     dd ?
  55. UserIDT dw ?            ; the idt register (base & limit)
  56.     dd ?
  57. UserLDT dw ?            ; the ldt register
  58. UserTR  dw ?            ; the tss register
  59. UserCR0    dd ?            ; control reg 0
  60. UserCR1    dd ?            ; control reg 1 - reserved
  61. UserCR2    dd ?            ; control reg 2
  62. UserCR3    dd ?            ; control reg 3
  63. UserDR0    dd ?            ; debug reg 0
  64. UserDR1    dd ?            ; debug reg 1
  65. UserDR2    dd ?            ; debug reg 2
  66. UserDR3    dd ?            ; debug reg 3
  67. UserDR4    dd ?            ; debug reg 4 - reserved
  68. UserDR5    dd ?            ; debug reg 5 - reserved
  69. UserDR6    dd ?            ; debug reg 6
  70. UserDR7    dd ?            ; debug reg 7
  71.     ; the following test registers are available only when 
  72.     ; Periscope/Remote is used with a protect mode target system
  73. UserTR4    dd ?            ; test reg 4 - 486 only
  74. UserTR5    dd ?            ; test reg 5 - 486 only
  75. UserTR6    dd ?            ; test reg 6 
  76. UserTR7    dd ?            ; test reg 7
  77.  
  78. ErrorCode dd ?            ; exception error code
  79.  
  80. else            ; if 16-bit
  81.  
  82. UserAX    dw ?            ; the ax register
  83. UserBX    dw ?            ; the bx register
  84. UserCX    dw ?            ; the cx register
  85. UserDX    dw ?            ; the dx register
  86. UserSP    dw ?            ; the sp register
  87. UserBP    dw ?            ; the bp register
  88. UserSI    dw ?            ; the si register
  89. UserDI    dw ?            ; the di register
  90. UserDS    dw ?            ; the ds register
  91. UserES    dw ?            ; the es register
  92. UserSS    dw ?            ; the ss register
  93. UserCS    dw ?            ; the cs register
  94. UserIP    dw ?            ; the ip register
  95. UserFL    dw ?            ; the flags register
  96.  
  97. endif
  98.  
  99. UserSegment dw ?        ; segment of address entered on user exit 
  100.                 ;  command line
  101.  
  102. if ps32
  103. UserOffset dd ?            ; offset of address entered on user exit 
  104. else                ;  command line
  105. UserOffset dw ?
  106. endif
  107.  
  108. UserBuffer dw 74/2 dup(?)    ; current Periscope command, terminated with a 
  109.                 ;  carriage return and a nul
  110.  
  111. UserPrevBuffer dw 74/2 dup(?)    ; previous Periscope command, starting with a
  112.                 ;  carriage return, and ending with a carriage
  113.                 ;  return and a nul. Should not be modified!
  114. UserArgs ends
  115.  
  116.     ; On entry, ES:BX points to a user service routine in Periscope. This
  117.     ; routine is accessed via a far call. Register AH is used to indicate
  118.     ; the function desired. When using this routine, all registers are
  119.     ; preserved. The functions available are:
  120.     ;
  121.     ; AH=1 -- display nul-terminated string at DS:SI. This function
  122.     ; uses the standard Periscope display handler to display a string
  123.     ; on the screen. The maximum length of the string is 83 characters,
  124.     ; including a carriage return, line feed, and nul. The string must end
  125.     ; with a nul (binary zero)!
  126.     ;
  127.     ; AH=2 -- get command string into UserBuffer. This function uses 
  128.     ; the standard Periscope keyboard handler to get an input string. The
  129.     ; maximum length of the string is 74 characters, including a carriage
  130.     ; return and a nul. Note that the new string is passed back at the
  131.     ; same location as when the User Exit was first activated.
  132.  
  133.     ; AH=3 -- search symbol table for nul-terminated string passed in
  134.     ; UserBuffer. This function returns the segment in UserSegment 
  135.     ; and the offset in UserOffset. If no symbol is found, the Carry flag 
  136.     ; is set.
  137.  
  138.     ; AH=4 -- search symbol table for symbol whose address is stored
  139.     ; at UserSegment:UserOffset. The name is returned in UserBuffer. If no
  140.     ; symbol is found, the Carry flag is set.
  141.  
  142.     ; AH=5 -- download and execute code on a Periscope remote driver.
  143.     ; DS:SI points to a string whose length (0-64) is in the first byte.
  144.     ; The following bytes are the code that is to be executed on the
  145.     ; remote machine.
  146.  
  147.     ; AH=6 -- upload string from a Periscope remote driver. ES:DI points
  148.     ; to a string whose length (0-64) is returned in the first byte.
  149.     ; The following bytes are the data that is passed up from the remote
  150.     ; system.
  151.  
  152.     ; AH=7 -- read a byte from a Periscope remote driver. ES:(E)DI points
  153.     ; to the memory location to be read. The value is returned in AL.
  154.  
  155.     ; AH=8 -- write the byte in AL to a Periscope remote driver. ES:(E)DI
  156.     ; points to the memory location to be written.
  157.  
  158.     ; On return from a USER BREAKPOINT, AL indicates whether or not the
  159.     ; routine got a 'hit'. If AL=1, then Periscope assumes a hit and stops.
  160.     ; Any other value is assumed not to be a hit and Periscope continues
  161.     ; the GT command, unless another breakpoint (e.g. BW) is taken.
  162.  
  163.     ; On return from a USER EXIT, AL indicates whether the exit code has
  164.     ; set a command to be executed by Periscope. If AL=2, Periscope reads
  165.     ; the command line passed back from the user exit. The command line
  166.     ; must start with a semi-colon and end with a carriage return.
  167.  
  168.     ; The values of registers other than AX, BX, SI, DS and ES on entry 
  169.     ; to the program are undefined.
  170.  
  171.     ; If your code will require more than 32 words of stack space, you
  172.     ; should switch to your own internal stack. Be sure that Periscope's
  173.     ; original stack is in place before returning to Periscope. All other
  174.     ; registers may be modified as needed.
  175.  
  176.     assume cs:cseg,ds:cseg,ss:nothing,es:nothing
  177.  
  178. start:    jmp transient        ; go to start-up code
  179.  
  180. intno    equ 60h         ; use interrupt 60h
  181. cr    equ 13            ; carriage return
  182. lf    equ 10            ; line feed
  183.  
  184. even
  185. pservice dd 0            ; periscope service routine's location
  186.  
  187. signature db 'P','S'            ; signature required by PS.COM - must be just
  188.                 ; before interrupt entry point!
  189.  
  190. resident:            ; interrupt entry point
  191.                 ; choose function based on value in ah
  192.     push si
  193.     mov si,offset pservice
  194.     mov cs:[si],bx        ; save service routine offset
  195.     mov cs:[si+2],es    ; save service routine segment
  196.     pop si
  197.  
  198.     cld            ; up periscope!
  199.  
  200.     cmp ah,1        ; ah=1?
  201.     jz send1        ; yes - demo user breakpoint
  202.  
  203.     cmp ah,2        ; ah=2?
  204.     jz send2        ; yes - test cs for range set by /u a
  205.  
  206.     cmp ah,9        ; ah=9?
  207.     jz send9        ; yes - demo user exit
  208.  
  209.     cmp ah,0ah        ; ah=a?
  210.     jz senda        ; yes - set cs range for use by 'bu 2'
  211.  
  212. ife ps32
  213.     cmp ah,0bh        ; ah=b?
  214.     jz sendb        ; yes - display BASIC style string
  215.  
  216.     cmp ah,0ch        ; ah=c?
  217.     jz sendc        ; yes - display BASIC PDS far string
  218. endif
  219.  
  220.     cmp ah,0eh        ; ah=e?
  221.     jz sende        ; yes - another user exit
  222.  
  223.     cmp ah,52h        ; ah=52h?
  224.     jz send52        ; yes - execute code on remote ps
  225.  
  226.     cmp ah,53h        ; ah=53h?
  227.     jz send53        ; yes - read/write memory on remote ps
  228.  
  229.     cmp ah,87h        ; ah=87h?
  230.     jz send87        ; yes - display 8087/80287 status
  231.  
  232.     cmp ah,88h        ; ah=88h?
  233.     jz send88        ; yes - display dos memory allocation
  234.  
  235.     cmp ah,0f0h        ; ah=f0 - ff?
  236.     jae special
  237.  
  238. exit:    iret            ; return to Periscope
  239.  
  240. special:jz sendf0        ; yes - process command line
  241.  
  242.     cmp ah,0f1h        ; ah=f1?
  243.     jz sendf1        ; yes - intercept short boot
  244.  
  245.     cmp ah,0f2h        ; ah=f2?
  246.     jz sendf2        ; yes - intercept normal boot
  247.  
  248.     cmp ah,0f3h        ; ah=f3?
  249.     jz sendf3        ; yes - intercept long boot
  250.  
  251.     iret
  252.  
  253. send1:    jmp func1        ; jump table - inelegant, but fast
  254. send2:    jmp func2
  255. send9:    jmp func9
  256. senda:    jmp funca
  257.  
  258. ife ps32
  259. sendb:    jmp funcb
  260. sendc:    jmp funcc
  261. endif
  262.  
  263. sende:    jmp funce
  264. send52: jmp func52
  265. send53: jmp func53
  266. send87: jmp func87
  267. send88: jmp func88
  268. sendf0: jmp funcf0
  269. sendf1: jmp funcf1
  270. sendf2: jmp funcf2
  271. sendf3: jmp funcf3
  272.  
  273.  
  274. indos    dd 0            ; pointer to in-dos flag
  275.  
  276. func1:                ; function 1
  277.     ; This is an example of a user breakpoint to check for dos availability.
  278.     ; It is invoked by specifying 'BU 1' and then using 'GT'.
  279.  
  280.     les di,cs:indos     ; get pointer to in-dos flag
  281.     cmp byte ptr es:[di],0    ; dos avail?
  282.     jnz exit1        ; no
  283.  
  284. if ps32
  285.     test word ptr [si.UserEFL],0200h ; interrupts enabled?
  286. else
  287.     test word ptr [si.UserFL],0200h ; interrupts enabled?
  288. endif
  289.  
  290.     jz exit1        ; no
  291.  
  292.     mov al,1        ; yes - it's a hit
  293.  
  294. exit1:    jmp exit
  295.  
  296. lowcs    dw 0            ; low value for cs test
  297. highcs    dw 0            ; high value for cs test
  298.  
  299. func2:                ; function 2
  300.     ; This is an example of a user *breakpoint* that checks the value of the
  301.     ; CS register versus a range set by user *exit* '/u a'.
  302.  
  303.     mov bx,[si.UserCS]     ; user's cs in bx
  304.     cmp bx,cs:lowcs     ; too low?
  305.     jb exit2        ; yes
  306.  
  307.     cmp bx,cs:highcs    ; too high?
  308.     ja exit2        ; yes
  309.  
  310.     mov al,1        ; got one
  311.  
  312. exit2:    jmp exit
  313.  
  314. commline  db ';dd 0:0',cr       ; ps command line - must start with a semi-colon
  315.                 ; and end with a carriage return
  316.  
  317. commlen equ 8            ; length of command line
  318.  
  319. func9:                ; function 9
  320.     ; This is an example of a user exit that stuffs a command into
  321.     ; Periscope's command line.
  322.  
  323.     mov di,si
  324.     add di,UserBuffer    ; point to ps command line
  325.     push ds
  326.     pop es            ; es:di point to ps command line
  327.  
  328.     push cs
  329.     pop ds
  330.     mov si,offset commline    ; ds:si point to new command
  331.  
  332.     mov cx,commlen        ; length must be <= 72 bytes!
  333.     rep movsb        ; copy command
  334.  
  335.     mov al,2        ; indicate that this is a command
  336.  
  337. exit9:    jmp exit
  338.  
  339. funca:                ; function a
  340.     ; This user *exit* sets the range of the CS register for use by the
  341.     ; user *breakpoint* 'bu 2'.
  342.  
  343.     mov ax,[si.UserSegment] ; get segment (low cs)
  344.     mov cs:lowcs,ax
  345.     mov ax,word ptr [si.UserOffset]    ; get offset (high cs)
  346.     mov cs:highcs,ax
  347.  
  348.     push cs
  349.     pop ds            ; ds=cs
  350.  
  351.     mov ax,lowcs        ; get low cs value
  352.     mov si,offset csval1
  353.     call convert        ; convert hex to ascii
  354.  
  355.     mov ax,highcs        ; get high cs value
  356.     mov si,offset csval2
  357.     call convert        ; convert hex to ascii
  358.  
  359.     mov si,offset csmsg
  360.     mov ah,1        ; display message
  361.     call [pservice]     ; call service routine
  362.  
  363. exita:    jmp exit
  364.  
  365. convert proc near        ; convert hex number in ax to ascii at [si]
  366.     push ax
  367.     xchg ah,al
  368.     call convertbyte    ; convert lo byte
  369.     pop ax
  370.                 ; convert hi byte
  371. convertbyte:
  372.     push bx
  373.     push cx
  374.     mov ah,0
  375.     mov bx,offset hextable
  376.     mov cl,4
  377.     shl ax,cl
  378.     shr al,cl
  379.     xlat
  380.     xchg ah,al
  381.     xlat
  382.     mov [si],ax
  383.     inc si
  384.     inc si
  385.     pop cx
  386.     pop bx
  387.     ret
  388. convert endp
  389.  
  390. hextable db '0123456789ABCDEF'  ; hex conversion table
  391. csmsg    db 'CS range is from '
  392. csval1    db '.... to '
  393. csval2    db '....',cr,lf,0
  394.  
  395. ife ps32
  396. funcb:                ; function b
  397.     ; This user exit displays a BASIC string for Quick Basic.
  398.     ; It is called using '/ub <name>'
  399.  
  400.     mov cs:NearString,1    ; set "near string" flag
  401.     jmp short CommonCode
  402.         
  403. funcc:                ; function c
  404.     ; This user exit display a BASIC PDS far string.
  405.     ; It is called using '/uc <name>'
  406.         
  407.     mov cs:NearString,0    ; reset the flag
  408.         
  409. CommonCode:            ; as in a cure for the common code?
  410.     mov bx,[si.UserOffset]    ; get symbol offset
  411.     cmp bx,0        ; offset zero?
  412.     jz funcb2        ; must not be a basic variable
  413.  
  414.     mov ds,[si.UserSegment]    ; get symbol segment
  415.     mov si,bx        ; ds:si point to symbol
  416.         
  417.     cmp cs:NearString,1    ; processing a near string?
  418.     jz DoNear
  419.         
  420.     ; Must be a far string
  421.     mov ax,[si]        ; Pointer to String length in string segment
  422.     mov bx,[si+2]        ; Pointer to string segment in (in DGROUP)
  423.     mov ds,[bx]        ; DS to string's segment
  424.     xchg ax,bx
  425.     mov bx,[bx]        ; Pointer to string's length in bx
  426.     mov cx,[bx]        ; String's length into cx
  427.     add bx,2        ; Add two bytes and that's the offset to the
  428.     mov si,bx        ;  string. Put it in si.
  429.     jmp short StringContinue
  430.         
  431. DoNear:
  432.     mov cx,[si]        ; get length in cx
  433.     mov si,[si+2]        ; get offset in si
  434.  
  435. StringContinue:
  436.     push cs
  437.     pop es            ; es=cs
  438.     mov di,offset outline
  439.  
  440.     push cx
  441.     push di
  442.     mov al,' '
  443.     mov cx,80
  444.     rep stosb        ; clear outline
  445.     pop di
  446.     pop cx
  447.  
  448.     jcxz funcb2        ; zero length - exit
  449.     cmp cx,80        ; 1-80?
  450.     jbe funcb1        ; yes
  451.  
  452.     mov cx,80        ; limit it
  453.  
  454. funcb1: rep movsb        ; copy name to outline
  455.  
  456.     mov si,offset outline
  457.  
  458. funcb3: mov ah,1
  459.     push cs
  460.     pop ds            ; ds=cs
  461.     call [pservice]     ; display it
  462.  
  463. exitb:    jmp exit
  464.  
  465. funcb2: mov si,offset nofind
  466.     jmp funcb3
  467.  
  468. nofind db 'Unknown symbol',cr,lf,0
  469. NearString db 0
  470. endif
  471.  
  472. funce:                ; function e (aka funky)
  473.     ; This is an example of a user exit that gets a symbol name and
  474.     ; then attempts to search the symbol table. If the symbol search
  475.     ; by name is successful, the symbol table is searched by address.
  476.  
  477.     push cs
  478.     pop ds
  479.  
  480.     mov si,offset prompt
  481.     mov ah,1        ; display message
  482.     call [pservice]     ; call service routine
  483.  
  484.     mov ah,2        ; get input string
  485.     call [pservice]     ; call service routine
  486.  
  487.     mov ah,3        ; search symbol table by name
  488.     call [pservice]     ; call service routine
  489.     jnc funce1        ; found it
  490.  
  491.     mov si,offset nofind1
  492.     mov ah,1        ; display message
  493.     call [pservice]     ; call service routine
  494.     jmp exite        ; quit
  495.  
  496. funce1: mov si,offset find1
  497.     mov ah,1        ; display message
  498.     call [pservice]     ; call service routine
  499.  
  500.     mov ah,4        ; search symbol table by address
  501.     call [pservice]     ; call service routine
  502.     jnc funce2        ; found it
  503.  
  504.     mov si,offset nofind2
  505.     jmp funce3
  506.  
  507. funce2: mov si,offset find2
  508.  
  509. funce3: mov ah,1        ; display message
  510.     call [pservice]     ; call service routine
  511.  
  512. exite:    jmp exit
  513.  
  514. prompt    db 'Symbol name? ',0
  515. nofind1 db 'Symbol not found by name',cr,lf,0
  516. find1    db 'Symbol found by name',cr,lf,0
  517. nofind2 db 'Symbol not found by address',cr,lf,0
  518. find2    db 'Symbol found by address',cr,lf,0
  519.  
  520. func52:             ; function 52
  521.     ; This is an example of a user exit that downloads some code to
  522.     ; a periscope remote driver and then runs that code. The routine
  523.     ; then reads the results of the code that was run.
  524.  
  525.     mov ax,cs
  526.     mov ds,ax
  527.     mov si,offset codesample; ds:si point to code string to be passed
  528.  
  529.     mov ah,5        ; download code
  530.     call [pservice]     ; call service routine
  531.  
  532.     mov ax,cs
  533.     mov es,ax
  534.     mov di,offset uplen
  535.  
  536.     mov ah,6        ; upload string from remote
  537.     call [pservice]     ; call service routine
  538.     cmp uplen,1        ; got 1 byte?
  539.     jnz exit52        ; no - error
  540.  
  541.     mov al,upstring     ; use first byte only
  542.     mov si,offset portval
  543.     call convertbyte    ; convert hex to ascii
  544.  
  545.     mov ah,1
  546.     mov si,offset portmsg
  547.     call [pservice]     ; display result
  548.  
  549. exit52: jmp exit
  550.  
  551. ife ps32
  552.  
  553. codesample proc near        ; this is for a real mode remote system
  554.     db offset endcode-$    ; length of code
  555.     mov al,1
  556.     stosb            ; output 1 byte
  557.     in al,21h         ; get value of port 21h
  558.     stosb            ; return byte in al
  559.     ret            ; must be a near return!
  560. endcode equ $-1
  561. codesample endp
  562.  
  563. else
  564.  
  565. codesample proc near        ; this is for a protected mode remote system
  566.     ; The following is not for the faint of heart. Since the code will
  567.     ; be running on a 32-bit protect mode system, you'll need to generate
  568.     ; full 32-bit code. One way to do it is to patch in any differences.
  569.  
  570.     db offset endcode-$    ; length of code
  571.     mov al,1
  572.     stosb            ; output 1 byte
  573.     in al,21h        ; get value of port 21h
  574.     stosb            ; return byte in al
  575.     retf            ; must be a far dword return!
  576. endcode equ $-1
  577. codesample endp
  578.  
  579. endif
  580.  
  581. uplen    db 0
  582. upstring db 0,0
  583.     dw 31 dup(0)        ; keep this after uplen
  584.  
  585. portmsg db 'The value read from port 21h on the remote system is '
  586. portval db '??H.',cr,lf,0
  587.  
  588. func53:             ; function 53
  589.     ; This is an example of a user exit that reads memory on
  590.     ; a periscope remote driver.
  591.  
  592.     mov ax,cs
  593.     mov ds,ax
  594.  
  595.     xor di,di
  596.     mov es,di        ; point to 0:0 (int 0)
  597.  
  598.     mov ah,7        ; read memory
  599.     call [pservice]     ; call service routine
  600.  
  601.     mov si,offset readvalue
  602.     call convertbyte    ; convert hex to ascii
  603.  
  604.     mov ah,1
  605.     mov si,offset readmsg
  606.     call [pservice]     ; display result
  607.  
  608. exit53: jmp exit
  609.  
  610. readmsg db 'The value at 0:0 is '
  611. readvalue db '??H.',cr,lf,0
  612.  
  613. func87:             ; function 87 - display 8087/80287 status
  614.     push cs
  615.     pop ds            ; ds=cs
  616.  
  617.     push ds
  618.     pop es            ; es=ds
  619.     call p330        ; clear output line
  620.  
  621.     cmp ndpfound,1        ; ndp found at start time?
  622.     jnz no87        ; no
  623.  
  624.     fstenv ndpctrl        ; save ndp environment
  625.     fldenv ndpctrl        ; restore it
  626.  
  627.     call p200        ; display control info
  628.     call p210        ; display status line
  629.     call p220        ; display ip, opcode, and dp
  630.     call p230        ; display tag words
  631.  
  632. exit87: jmp exit
  633.  
  634. no87:    mov ah,1
  635.     mov si,offset no87msg
  636.     call [pservice]     ; display line
  637.     jmp exit87
  638.  
  639. func88:             ; function 88 - display dos memory allocation
  640.  
  641.     push cs
  642.     pop ds            ; ds=cs
  643.     cmp dosver,2        ; dos 2.x?
  644.     jz exit88        ; yes - exit
  645.  
  646.     xor di,di
  647.     mov priorseg,di
  648.     mov pspseg,di
  649.     mov ax,dosmemseg    ; get start seg for dos memory alloc blocks
  650.     mov lastseg,ax
  651.     call p110        ; get segment for dos
  652.     jc exit88        ; error
  653.  
  654.     mov dx,es
  655.     inc dx
  656.     mov pspseg,dx
  657.     mov si,offset command
  658.     mov di,offset outline+6
  659.     push cs
  660.     pop es            ; es=cs
  661.     mov cx,14
  662.     rep movsb        ; copy command over
  663.     jmp p104        ; continue
  664.  
  665. exit88: jmp exit
  666.  
  667. p101:    push cs
  668.     pop ds            ; ds=cs
  669.     xor di,di
  670.     mov es,priorseg
  671.     cmp byte ptr es:[di],5ah    ; end?
  672.     jz exit88        ; yes
  673.  
  674.     call p110        ; get segment
  675.     jc exit88        ; error
  676.  
  677.     mov dx,es
  678.     inc dx
  679.     mov pspseg,dx
  680.     mov ds,dx        ; ds=prior es
  681.     mov si,2ch
  682.     lodsw            ; get environment
  683.     cmp ax,0        ; nul?
  684.     jz exit88        ; yes - exit
  685.  
  686.     mov ds,ax
  687.     xor si,si
  688.  
  689. p102:    lodsb            ; search for nul
  690.     cmp al,0
  691.     jnz p102
  692.  
  693.     lodsb            ; got one - look for second
  694.     cmp al,0
  695.     jnz p102
  696.  
  697.     lodsw            ; look for 1,0
  698.  
  699.     mov cx,80        ; max length
  700.     mov di,offset outline
  701.     push cs
  702.     pop es            ; es=cs
  703.  
  704.     mov al,' '
  705.     push cx
  706.     rep stosb        ; clear output area
  707.     pop cx
  708.     mov di,offset outline+6
  709.  
  710. p103:    lodsb            ; get char
  711.     cmp al,0        ; end?
  712.     jz p104         ; yes
  713.  
  714.     stosb            ; save char
  715.     loop p103        ; continue
  716.  
  717. p104:    push cs
  718.     pop ds            ; get orig ds back
  719.  
  720.     mov ax,pspseg
  721.     mov si,offset outline
  722.     call convert        ; convert psp
  723.  
  724.     mov ah,1
  725.     mov si,offset outline
  726.     call [pservice]     ; display line
  727.     jmp p101
  728.  
  729. p110    proc near
  730.     mov ax,lastseg
  731.     xor di,di        ; be sure
  732.  
  733. p111:    mov es,ax        ; get segment
  734.     add ax,es:[di+3]    ; add next segment into ax
  735.     inc ax            ; plus one
  736.     mov bx,es:[di+1]    ; get psp seg
  737.     mov cx,es        ; get current segment
  738.     cmp byte ptr es:[di],4dh; mem alloc block?
  739.     jz p112         ; yes
  740.  
  741.     cmp byte ptr es:[di],5ah ; end of chain?
  742.     jnz p113        ; no - error
  743.  
  744. p112:    inc cx            ; current segment plus one
  745.     cmp bx,cx        ; psp seg?
  746.     jnz p111        ; no - keep on
  747.  
  748.     mov lastseg,ax
  749.     mov priorseg,es
  750.     clc
  751.     ret
  752.  
  753. p113:    stc
  754.     ret
  755. p110    endp
  756.  
  757. dosver    db 0
  758. dosmemseg dw 0
  759. lastseg dw 0
  760. priorseg dw 0
  761. pspseg    dw 0
  762. command db 'COMMAND.COM',cr,lf,0
  763.  
  764. funcf0:             ; function f0
  765.     ; This is an example of a reserved user exit. If a user exit is
  766.     ; installed, function F0H is activated after each command is entered,
  767.     ; but before it is processed by Periscope. At this time, the user exit
  768.     ; can modify the command as desired, using the command area defined
  769.     ; above. No registers need to be set -- just modify the command line
  770.     ; as desired.
  771.  
  772.     add si,20h        ; point to ps command line
  773.     mov ax,[si]        ; get first word
  774.     cmp ax,'..'             ; double dot?
  775.     jnz exitf0        ; no
  776.  
  777.     mov word ptr [si],'dd'  ; yes - convert it to dd
  778.  
  779. exitf0: jmp exit
  780.  
  781. funcf1:             ; function f1
  782.     ; This is an example of a reserved user exit. If a user exit is
  783.     ; installed, function F1H is activated before a short boot.
  784.  
  785.     call beep        ; beep once
  786.     jmp exit
  787.  
  788. funcf2:             ; function f2
  789.     ; This is an example of a reserved user exit. If a user exit is
  790.     ; installed, function F2H is activated before a normal boot.
  791.  
  792.     call beep        ; beep twice
  793.     call beep
  794.     jmp exit
  795.  
  796. funcf3:             ; function f3
  797.     ; This is an example of a reserved user exit. If a user exit is
  798.     ; installed, function F3H is activated before a long boot.
  799.  
  800.     call beep        ; beep three times
  801.     call beep
  802.     call beep
  803.     jmp exit
  804.  
  805. beep    proc near
  806.     push ax
  807.     push bx
  808.     push cx
  809.     push es
  810.     pushf
  811.     sti
  812.  
  813.     xor ax,ax
  814.     mov es,ax
  815.     mov bx,46ch        ; offset of low timer word
  816.  
  817.     mov al,0b6h
  818.     out 43h,al        ; set timer
  819.     mov al,33h
  820.     out 42h,al
  821.     jmp $+2         ; wait
  822.  
  823.     mov al,3
  824.     out 42h,al
  825.     in al,61h
  826.     mov ah,al        ; save orig value
  827.     or al,3
  828.     jmp $+2         ; wait
  829.  
  830.     call beepa        ; sync it
  831.  
  832.     out 61h,al        ; speaker on
  833.     call beepa        ; wait 1
  834.  
  835.     mov al,33h
  836.     out 42h,al
  837.     jmp $+2
  838.  
  839.     mov al,6
  840.     out 42h,al
  841.     call beepa        ; wait 1
  842.  
  843.     mov al,ah
  844.     out 61h,al        ; back to initial value
  845.  
  846.     popf
  847.     pop es
  848.     pop cx
  849.     pop bx
  850.     pop ax
  851.     ret
  852.  
  853. beepa:    mov cx,es:[bx]        ; get timer value
  854.  
  855. beepb:    jmp $+2
  856.     cmp cx,es:[bx]        ; same?
  857.     jz beepb        ; yes - wait
  858.  
  859.     ret
  860. beep    endp
  861.  
  862.     ; control word equates
  863. nbic    equ 1000h        ; ic - bit 12
  864. nbrc    equ 0c00h        ; rc - bits 10,11
  865. nbpc    equ 0300h        ; pc - bits 8,9
  866. nbpm    equ 0020h        ; pm - bit 5
  867. nbum    equ 0010h        ; um - bit 4
  868. nbom    equ 0008h        ; om - bit 3
  869. nbzm    equ 0004h        ; zm - bit 2
  870. nbdm    equ 0002h        ; dm - bit 1
  871. nbim    equ 0001h        ; im - bit 0
  872.  
  873.     ; status word equates
  874. nbby    equ 8000h        ; busy
  875. nbc3    equ 4000h        ; cond code 3
  876. nbtop    equ 3800h        ; top of stack
  877. nbc2    equ 0400h        ; cond code 2
  878. nbc1    equ 0200h        ; cond code 1
  879. nbc0    equ 0100h        ; cond code 0
  880. nbes    equ 0080h        ; err status
  881.  
  882.     ; control word text
  883. ndpc1    db 'Ctrl: Infin=',0
  884. ndpc2    db '  Round=',0
  885. ndpc3    db '  Prec=',0
  886. ndpc4    db '  Flags=',0
  887.  
  888.     ; status word text
  889. ndps1    db 'Stat: Cond=',0
  890. ndps2    db '   Stacktop=',0
  891.  
  892.     ; misc text
  893. ndpip    db 'IP=',0
  894. ndpop    db 'Opcode=',0
  895. ndpdp    db 'DP=',0
  896. ndptag    db 'Tag: ',0
  897. ndpflags db 'PrecUndrOverZeroDen Inv ' ; possible flags
  898. ndpbusy db 'Busy'
  899. ndperr    db 'Err '
  900. ndpinf0 db 'Proj'
  901. ndpinf1 db 'Aff '
  902. ndprnd    db 'NearDownUp  Chop'   ; round types
  903. ndpprec db 'Short?????Long Temp ' ; precision types
  904. ndptval db 'ValidZero InfinEmpty' ; tag values
  905.  
  906.     ; ndp save area
  907. ndpctrl dw 0            ; save area - control word
  908. ndpstat dw 0            ; status word
  909. ndptagw dw 0            ; tag word
  910. ndpip1    dw 0            ; inst ptr 1
  911. ndpip2    dw 0            ; inst ptr 2
  912. ndpdp1    dw 0            ; data ptr 1
  913. ndpdp2    dw 0            ; data ptr 2
  914.  
  915. no87msg db 'No numeric processor found',cr,lf,0
  916. ndpfound db 0            ; 1 if ndp found
  917. ndpstate dw 0            ; startup test word
  918.  
  919. outline db ' ',' '
  920.     dw 39 dup('  ')     ; output work line
  921.     db cr,lf,0
  922.  
  923. p200    proc near        ; display control info
  924.     mov ax,ndpctrl
  925.     mov si,offset ndpc1
  926.     call p300        ; copy control header
  927.     mov si,offset ndpinf0    ; assume projective
  928.     test ax,nbic        ; proj?
  929.     jz p201         ; yes
  930.  
  931.     mov si,offset ndpinf1    ; no
  932.  
  933. p201:    movsw            ; copy infinity type
  934.     movsw
  935.  
  936.     mov si,offset ndpc2
  937.     call p300        ; copy round header
  938.     mov si,offset ndprnd    ; assume near
  939.  
  940.     mov bx,ax        ; get word in bx
  941.     and bx,nbrc        ; clear other bits
  942.     xchg bh,bl        ; times four as is
  943.     add si,bx
  944.     movsw            ; copy round type
  945.     movsw
  946.  
  947.     mov si,offset ndpc3
  948.     call p300        ; copy precision header
  949.     mov si,offset ndpprec
  950.     mov bx,ax
  951.     and bx,nbpc
  952.     xchg bh,bl
  953.     mov cx,bx
  954.     shl bx,1        ; times 2
  955.     shl bx,1        ; times 4
  956.     add bx,cx        ; times 5
  957.     add si,bx
  958.     movsw            ; copy precision type
  959.     movsw
  960.     movsb
  961.  
  962.     call p320        ; display flags
  963.     call p340        ; print line
  964.     ret
  965. p200    endp
  966.  
  967. p210    proc near        ; display status info
  968.     mov ax,ndpstat
  969.     mov si,offset ndps1
  970.     call p300        ; copy status header
  971.     test ax,nbc3        ; cc3 on?
  972.     call p310        ; print result
  973.     test ax,nbc2        ; cc2 on?
  974.     call p310
  975.     test ax,nbc1
  976.     call p310
  977.     test ax,nbc0
  978.     call p310
  979.  
  980.     mov si,offset ndps2
  981.     call p300        ; copy stacktop header
  982.     mov bx,ax
  983.     and bx,nbtop
  984.     shr bx,1
  985.     shr bx,1
  986.     shr bx,1        ; in bh
  987.     add bh,'0'              ; make ascii
  988.     mov [di],bh
  989.     inc di
  990.     inc di
  991.     inc di
  992.  
  993.     test ax,nbby        ; busy?
  994.     jnz p211        ; yes
  995.  
  996.     add di,4        ; no
  997.     jmp short p212
  998.  
  999. p211:    mov si,offset ndpbusy
  1000.     movsw
  1001.     movsw
  1002.  
  1003. p212:    inc di
  1004.     inc di
  1005.  
  1006.     test ax,nbes        ; error?
  1007.     jnz p213        ; yes
  1008.  
  1009.     inc di
  1010.     inc di
  1011.     inc di
  1012.     jmp short p214
  1013.  
  1014. p213:    mov si,offset ndperr
  1015.     movsw
  1016.     movsb
  1017.  
  1018. p214:    inc di
  1019.     call p320        ; display flags
  1020.     call p340        ; display line
  1021.     ret
  1022. p210    endp
  1023.  
  1024. p220    proc near        ; display ip, opcode, and dp
  1025.     mov si,offset ndpip
  1026.     call p300        ; copy ip header
  1027.     mov ax,ndpip2        ; get ip
  1028.     mov cx,4
  1029.     rol ax,cl        ; address in low 4 bits
  1030.     call p350        ; display nibble
  1031.     mov ax,ndpip1        ; get lower part of ip
  1032.     call p360        ; display word
  1033.  
  1034.     mov si,offset ndpop
  1035.     call p300        ; copy opcode header
  1036.     mov ax,ndpip2
  1037.     and ax,07ffh        ; clear out ip part
  1038.     or ax,0d800h        ; make it an esc instruction
  1039.     call p360        ; display word
  1040.  
  1041.     mov si,offset ndpdp
  1042.     call p300        ; copy dp header
  1043.     mov ax,ndpdp2        ; get dp
  1044.     mov cx,4
  1045.     rol ax,cl        ; address in low 4 bits
  1046.     call p350        ; display nibble
  1047.     mov ax,ndpdp1        ; get lower part of dp
  1048.     call p360        ; display word
  1049.  
  1050.     call p340        ; display line
  1051.     ret
  1052. p220    endp
  1053.  
  1054. p230    proc near        ; display tag word
  1055.     mov si,offset ndptag
  1056.     call p300        ; copy tag header
  1057.     mov ax,ndptagw        ; get tag word
  1058.     mov cx,8
  1059.  
  1060. p231:    rol ax,1
  1061.     rol ax,1        ; get next tag word
  1062.     push ax
  1063.     and ax,3
  1064.     mov bx,ax
  1065.     shl ax,1
  1066.     shl ax,1
  1067.     add bx,ax        ; times five
  1068.     mov si,offset ndptval    ; point to tag values
  1069.     add si,bx
  1070.     movsw
  1071.     movsw
  1072.     movsb            ; copy to output
  1073.     inc di
  1074.     inc di            ; two spaces
  1075.     pop ax
  1076.     loop p231
  1077.  
  1078.     call p340        ; display line
  1079.     ret
  1080. p230    endp
  1081.  
  1082. p300    proc near        ; copy to output line
  1083.     push ax
  1084.  
  1085. p301:    lodsb            ; get byte
  1086.     cmp al,0        ; end?
  1087.     jz p305         ; yes
  1088.  
  1089.     stosb            ; no - save it
  1090.     jmp p301        ; continue
  1091.  
  1092. p305:    pop ax
  1093.     ret
  1094. p300    endp
  1095.  
  1096. p310    proc near        ; print 0 if zr, else 1
  1097.     mov bl,'0'
  1098.     jz p315
  1099.  
  1100.     mov bl,'1'
  1101.  
  1102. p315:    mov [di],bl
  1103.     inc di
  1104.     ret
  1105. p310    endp
  1106.  
  1107. p320    proc near        ; display flags
  1108.     mov si,offset ndpc4
  1109.     call p300        ; copy flags header
  1110.     mov si,offset ndpflags
  1111.     mov bx,nbpm        ; start w/ pm
  1112.     mov cx,6        ; six flags
  1113.  
  1114. p321:    test ax,bx        ; bit on?
  1115.     jnz p322        ; yes
  1116.  
  1117.     add si,4        ; next name
  1118.     add di,4
  1119.     jmp short p323
  1120.  
  1121. p322:    movsw            ; yes - copy it
  1122.     movsw
  1123.  
  1124. p323:    inc di            ; skip one
  1125.     shr bx,1        ; next test
  1126.     loop p321
  1127.     ret
  1128.  
  1129. p320    endp
  1130.  
  1131. p330    proc near        ; clear output line
  1132.     mov di,offset outline
  1133.     push di
  1134.     mov cx,80/2        ; length
  1135.     mov ax,'  '             ; spaces
  1136.     rep stosw        ; init to spaces
  1137.     pop di
  1138.     ret
  1139. p330    endp
  1140.  
  1141. p340    proc near        ; print output line
  1142.     mov ah,1        ; use periscope display
  1143.     mov si,offset outline    ; ds:si point to string
  1144.     call [pservice]     ; call periscope service routine
  1145.     call p330
  1146.     ret
  1147. p340    endp
  1148.  
  1149. p350    proc near        ; display nibble
  1150.     push ax
  1151.     and ax,0fh
  1152.     cmp ax,9        ; 0 to 9?
  1153.     ja p351         ; no - a to f
  1154.  
  1155.     add ax,'0'              ; convert to ascii
  1156.     jmp short p352
  1157.  
  1158. p351:    add ax,55        ; a - f
  1159.  
  1160. p352:    stosb            ; save byte
  1161.     pop ax
  1162.     ret
  1163. p350    endp
  1164.  
  1165. p360    proc near        ; display word
  1166.     mov bx,4        ; counter
  1167.  
  1168. p361:    rol ax,cl        ; move to low nibble
  1169.     call p350        ; display it
  1170.     dec bx
  1171.     jnz p361        ; not done
  1172.  
  1173.     inc di
  1174.     inc di            ; two spaces
  1175.     ret
  1176. p360    endp
  1177.  
  1178. transient:            ; end of resident code and
  1179.                 ; start of transient code
  1180.  
  1181.     cld            ; up periscope!
  1182.  
  1183.     ; test for numeric processor
  1184.     fninit            ; initialize it - no wait
  1185.     mov cx,20
  1186.     loop $            ; wait around for command to take
  1187.  
  1188.     mov bx,offset ndpstate
  1189.     fnstcw [bx]        ; store control word - no wait
  1190.     mov cx,20
  1191.     loop $            ; wait around
  1192.  
  1193.     mov ax,[bx]        ; get value
  1194.     and ax,0f3fh
  1195.     cmp ax,033fh        ; ndp found?
  1196.     jnz trans2        ; no
  1197.  
  1198.     mov ndpfound,1        ; yes
  1199.  
  1200. trans2:    ; init variables for function 88
  1201.     mov ah,30h
  1202.     int 21h         ; get DOS version
  1203.     mov dosver,al
  1204.  
  1205.     push es
  1206.     mov ah,52h
  1207.     mov bx,cs
  1208.     int 21h         ; get dos memory block pointer
  1209.     mov ax,es:[bx-2]
  1210.     mov dosmemseg,ax
  1211.     pop es
  1212.  
  1213.     mov ah,34h        ; set in-dos pointer
  1214.     int 21h
  1215.     mov si,offset indos
  1216.     mov [si],bx        ; save offset
  1217.     mov [si+2],es        ; and segment for user breakpoint 1
  1218.  
  1219.     xor ax,ax
  1220.     mov es,ax
  1221.     mov di,intno        ; get int number
  1222.     shl di,1
  1223.     shl di,1        ; times 4
  1224.  
  1225.     cli            ; no interrupts
  1226.     mov ax,offset resident    ; point interrupt to resident code
  1227.     stosw            ; set offset
  1228.     mov ax,ds
  1229.     stosw            ; and segment
  1230.     sti            ; interrupts back on
  1231.  
  1232.     mov dx,offset transient
  1233.     int 27h         ; stay resident
  1234.  
  1235. userexit endp
  1236. cseg    ends
  1237. end    userexit
  1238.